/*!
 Temelia - Vector performance tests.

 Copyright (C) 2008 Ceata (http://cod.ceata.org/proiecte/temelia).

 @author Dascalu Laurentiu

 This program is free software; you can redistribute it and
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "include/performance.hpp"
#include "include/testutil.hpp"

#include <vector>
#include <algorithm>

extern "C"
{
#include <temelia/vector.h>
}

// ==== temelia vector's functions ====
static void temelia_vector_push_back(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, &i);

	vector_delete(temelia_vector);
}

static void temelia_vector_push_front(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_front(temelia_vector, &i);

	vector_delete(temelia_vector);
}

static void temelia_vector_push_before(int n)
{
	vector_t temelia_vector = vector_new(n);

	vector_push_back(temelia_vector, default_collection[0]);

	for (int i = 1; i < n; i++)
		vector_push_before(temelia_vector, default_collection[i],
				vector_get_key_at(temelia_vector, i - 1), int_compare, NULL);

	vector_delete(temelia_vector);
}

static void temelia_vector_push_after(int n)
{
	vector_t temelia_vector = vector_new(n);

	vector_push_back(temelia_vector, default_collection[0]);

	for (int i = 1; i < n; i++)
		vector_push_after(temelia_vector, default_collection[i],
				vector_get_key_at(temelia_vector, i - 1), int_compare, NULL);

	vector_delete(temelia_vector);
}

static void temelia_vector_remove_key(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	for (int i = 0; i < n; i++)
		vector_remove_key(temelia_vector, vector_get_key_at(temelia_vector, n
				- i - 1), int_compare, NULL);

	vector_delete(temelia_vector);
}

static void temelia_vector_remove_key_at(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	for (int i = 0; i < n; i++)
		vector_remove_key_at(temelia_vector, n - i - 1);

	vector_delete(temelia_vector);
}

static void temelia_vector_pop_back(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	for (int i = 0; i < n; i++)
		vector_pop_back(temelia_vector);

	vector_delete(temelia_vector);
}

static void temelia_vector_pop_front(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	for (int i = 0; i < n; i++)
		vector_pop_front(temelia_vector);

	vector_delete(temelia_vector);
}

static void temelia_vector_search(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	for (int i = 0; i < n; i++)
		vector_search(temelia_vector, vector_get_key_at(temelia_vector, i % n),
				int_compare, NULL);

	vector_delete(temelia_vector);
}

static void temelia_vector_sort(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	vector_sort(temelia_vector, int_compare, NULL);
	vector_delete(temelia_vector);
}

static void iterating_function(void *key, void *context)
{
	// do nothing...
}

static void temelia_vector_iterate(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	vector_iterate(temelia_vector, iterating_function, NULL);
	vector_delete(temelia_vector);
}

static void temelia_vector_min(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	vector_min(temelia_vector, int_compare, NULL);
	vector_delete(temelia_vector);
}

static void temelia_vector_max(int n)
{
	vector_t temelia_vector = vector_new(n);

	for (int i = 0; i < n; i++)
		vector_push_back(temelia_vector, default_collection[i]);

	vector_max(temelia_vector, int_compare, NULL);
	vector_delete(temelia_vector);
}

// ==== STL vector's functions ====
static void stl_vector_push_back(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(&i);
}

static void stl_vector_push_front(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.insert(stl_vector.begin(), &i);
}

static void stl_vector_push_before(int n)
{
	std::vector<int *> stl_vector;

	stl_vector.push_back(default_collection[0]);

	for (int i = 1; i < n; i++)
		stl_vector.insert(stl_vector.begin() + i - 1, default_collection[i]);

}

static void stl_vector_push_after(int n)
{
	std::vector<int *> stl_vector;

	stl_vector.push_back(default_collection[0]);
	stl_vector.push_back(default_collection[1]);

	for (int i = 2; i < n; i++)
		stl_vector.insert(stl_vector.begin() + i - 1, default_collection[i]);
}

static void stl_vector_remove_key(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		stl_vector.erase(std::find(stl_vector.begin(), stl_vector.end(),
				default_collection[n - i - 1]));
}

static void stl_vector_remove_key_at(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		stl_vector.erase(stl_vector.begin() + n - i - 1);
}

static void stl_vector_pop_back(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		stl_vector.pop_back();
}

static void stl_vector_pop_front(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		stl_vector.erase(stl_vector.begin());
}

static void stl_vector_search(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		std::find(stl_vector.begin(), stl_vector.end(), default_collection[i]);
}

static bool my_comparison_function(int *x, int *y)
{
	return *(int *) x < *(int *) y;
}

static void stl_vector_sort(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	sort(stl_vector.begin(), stl_vector.end(), my_comparison_function);
}

void my_function(int *i)
{

}

static void stl_vector_iterate(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		std::for_each(stl_vector.begin(), stl_vector.end(), my_function);
}

static void stl_vector_min(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		std::min_element(stl_vector.begin(), stl_vector.end());
}

static void stl_vector_max(int n)
{
	std::vector<int *> stl_vector;

	for (int i = 0; i < n; i++)
		stl_vector.push_back(default_collection[i]);

	for (int i = 0; i < n; i++)
		std::max_element(stl_vector.begin(), stl_vector.end());

}

void TemeliaPerformance::pt_vector()
{
	TestUnit testUnit("vector");

	GENERATE_TEMELIA_TEST(testUnit, "push_back", vector_push_back);
	GENERATE_TEMELIA_TEST(testUnit, "pop_back", vector_pop_back);
	GENERATE_TEMELIA_TEST(testUnit, "iterate", vector_iterate);
	GENERATE_TEMELIA_TEST(testUnit, "max", vector_max);
	GENERATE_TEMELIA_TEST(testUnit, "min", vector_min);

	GENERATE_STL_TEST(testUnit, "push_back", vector_push_back);
	GENERATE_STL_TEST(testUnit, "pop_back", vector_pop_back);
	GENERATE_STL_TEST(testUnit, "iterate", vector_iterate);
	GENERATE_STL_TEST(testUnit, "max", vector_max);
	GENERATE_STL_TEST(testUnit, "min", vector_min);

#ifndef CLUSTER_RUNNING
	ntests = 8;
#endif

	GENERATE_TEMELIA_TEST(testUnit, "push_front", vector_push_front);
	GENERATE_TEMELIA_TEST(testUnit, "push_before", vector_push_before);
	GENERATE_TEMELIA_TEST(testUnit, "push_after", vector_push_after);
	GENERATE_TEMELIA_TEST(testUnit, "remove_key", vector_remove_key);
	GENERATE_TEMELIA_TEST(testUnit, "remove_key_at", vector_remove_key_at);
	GENERATE_TEMELIA_TEST(testUnit, "pop_front", vector_pop_front);
	GENERATE_TEMELIA_TEST(testUnit, "search", vector_search);
	GENERATE_TEMELIA_TEST(testUnit, "sort", vector_sort);

	GENERATE_STL_TEST(testUnit, "push_front", vector_push_front);
	GENERATE_STL_TEST(testUnit, "push_before", vector_push_before);
	GENERATE_STL_TEST(testUnit, "push_after", vector_push_after);
	GENERATE_STL_TEST(testUnit, "remove_key", vector_remove_key);
	GENERATE_STL_TEST(testUnit, "remove_key_at", vector_remove_key_at);
	GENERATE_STL_TEST(testUnit, "pop_front", vector_pop_front);
	GENERATE_STL_TEST(testUnit, "search", vector_search);
	GENERATE_STL_TEST(testUnit, "sort", vector_sort);

	testUnit.write(fout);
}
